#pragma once
#include <iostream>
#include <memory>
#include <unordered_map>
#include "Eoller.hpp"
#include "Connection.hpp"

class Reactor
{
public:
    Reactor() : _running(false), _epoller(std::make_unique<Epoller>())
    {
    }

    void Init()
    {
        _epoller->Create();
    }

    bool ExistFd(int fd)
    {
        return !(_connections.find(fd) == _connections.end());
    }

    void AddConnection(Connection *conn, uint32_t event)
    {
        if (conn == nullptr)
            return;
        if (ExistFd(conn->GetFd()))
            return;

        _connections[conn->GetFd()] = conn;
        _epoller->Add(conn->GetFd(), event);
    }

    void ModConnection(Connection *conn, bool is_reader, bool is_writer)
    {
        if (conn == nullptr)
            return;
        if (!ExistFd(conn->GetFd()))
            return;

        uint32_t event = (is_reader ? EPOLLIN : 0) | (is_writer ? EPOLLOUT : 0) | EPOLLET;
        _connections[conn->GetFd()]->SetEvent(event);
        _epoller->Mod(conn->GetFd(), event);
    }

    void DelConnection(Connection *conn)
    {
        if (conn == nullptr)
            return;
        if (!ExistFd(conn->GetFd()))
            return;

        _connections.erase(conn->GetFd());
        _epoller->Del(conn->GetFd());
    }

    // bool ExsistConnectio(Connection* conn)
    // {
    //     if(!conn) return false;
    //     if(!ExsistFd(conn->GetFd())) return false;

    //     return true;
    // }

    void LoopOnce()
    {
        int n = _epoller->Wait();
        epoll_events_array_ptr array = _epoller->GetEpollEvents();
        for (int i = 0; i < n; i++)
        {
            int fd = array[i].data.fd;
            uint32_t event = array[i].events;

            // 假如epoll模型获取事件出现错误，转化为读写错误
            if (event & EPOLLERR || event & EPOLLHUP)
            {
                event |= (EPOLLIN | EPOLLOUT);
            }

            if (ExistFd(fd) && event & EPOLLIN)
            {
                _connections[fd]->GetReader()(_connections[fd]);
            }
            if (ExistFd(fd) && event & EPOLLOUT)
            {
                // std::cout << "写事件关心就绪" <<std::endl;
                _connections[fd]->GetWriter()(_connections[fd]);
            }
        }
    }

    void Dispatch()
    {
        _running = true;
        while (_running)
        {
            LoopOnce();
            // _epoller->PrintBug();
            // sleep(1);
        }
        _running = false;
    }

    ~Reactor() {}

private:
    bool _running;

    std::unique_ptr<Epoller> _epoller;

    std::unordered_map<int, Connection *> _connections;
};